Skip to main content

IPF Data Provider

Provider supplying a list of data about trading instruments that can be set on the chart, along with their trading hours.

import Combine
/// Protocol for receiving instrument profile data - array of InstrumentData.
///
/// When loading DXChart framework, an array of instruments, their descriptions, etc. are taken from this interface
///
/// When connecting DXChart framework, developer can implement this interface or use the default implementation [link on the default implementation] and pass it to the framework using DXChart.DataProvider class
public protocol IPFDataProvider {
/// Publisher of receiving instrument profile data.
///
/// Instrument profile data is represented by array of InstrumentData.
var dataPublisher: AnyPublisher<Result<[DXChart.Instrument], Error>, Never> { get }
/// Provide information about loading status.
var isLoading: AnyPublisher<Bool, Never> { get }
}

Possible Server Errors:

public enum ServerError: Error {
case unknown
case noData
case parseError
case urlError
case tooManyRequests
case unknown
}

InstrumentData structure uses following parameters:

/// A structure that represents a financial instrument.
///
/// The `Instrument` struct stores essential information about a financial instrument, such as its type, symbol, description, time zone, price increments, and trading schedule.
///
/// - Note: This struct conforms to `Codable`, allowing it to be easily encoded and decoded for serialization purposes.
///
/// - Properties:
/// - `type`: The type of the instrument (e.g., `STOCK`, `CRYPTO`).
/// - `symbol`: The symbol of the instrument (e.g., `GOOG`, `TSLA`, `AAPL`).
/// - `description`: A description of the instrument (e.g., `Alphabet Inc. - Class C Capital Stock`).
/// - `timezone`: The time zone associated with the instrument (e.g., `America/New_York`).
/// - `priceIncrements`: The minimum price increment for the instrument (e.g., `0.01`).
/// - `schedule`: The trading schedule for the instrument, including session breaks and extended hours. This property is optional.
public struct Instrument: Codable {
/// The type of the instrument (e.g., `STOCK`, `CRYPTO`).
public var type: String
/// The symbol of the instrument (e.g., `GOOG`, `TSLA`, `AAPL`).
public var symbol: String
/// A description of the instrument (e.g., `Alphabet Inc. - Class C Capital Stock`).
public var description: String
/// The time zone associated with the instrument (e.g., `America/New_York`).
public var timezone: String
/// The minimum price increment for the instrument (e.g., `0.01`).
public var priceIncrements: String
/// The trading schedule for the instrument, including session breaks and extended hours.
/// This property is optional and can be `nil` if no schedule is available.
public var schedule: Trading.Schedule?
}
@available(*, deprecated, renamed: "Instrument", message: "This typealias is deprecated and will be removed in a future version. Use `Instrument` directly instead.")
/// A deprecated typealias for `Instrument`.
///
/// This typealias is provided for backward compatibility and will be removed in a future version.
/// Use `Instrument` directly instead.
public typealias InstrumentData = Instrument
  • type - Type of instrument (f.e. STOCK, CRYPTO)
  • symbol - Symbol of the instrument (e.g., "GOOG", "TSLA", "AAPL").
  • description - Description of the instrument (e.g., "Alphabet Inc. - Class C Capital Stock").
  • timezone - Raw data about timezone of the instrument (e.g., "Asia/Istanbul", "America/New_York").
  • sessionBreaks - Parsed trading hours of the instrument. (e.g., "BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800)").
  • priceIncrements - Minimal price increments of the instrument (e.g., "0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5").

Received data about instruments is displayed in the list of instruments:

image-2024-1-29_0-40-22

Default implementation

If you haven't implemented an IPF data provider earlier and are using `DXFeedFramework` to retrieve data, you can use our default provider. To work with it and `DXFeedFramework`, you need an `IPF Address` to obtain instrument information. Please contact your DXFeed sales manager or visit https://dxfeed.com/contact-sales/ for assistance.

Default implementation code:

import Combine
import DXChart
import DXFeedFramework
final class DXFeedIPFDataProvider: DXChart.IPFDataProvider {
typealias IPFResult = Result<[DXChart.Instrument], Error>
let address: String
private let dataStorage = DataStorage.shared
private var instruments: [DXChart.Instrument]?
private var _isLoading = PassthroughSubject<Bool, Never>()
var isLoading: AnyPublisher<Bool, Never> {
_isLoading.eraseToAnyPublisher()
}
lazy var dataPublisher: AnyPublisher<IPFResult, Never> = Deferred { [weak self] in
Future<IPFResult, Never> { promise in
guard let self else { return promise(.success(.failure(ServerError.noData)))}
if let instruments = self.instruments {
return promise(.success(.success(instruments)))
}
DispatchQueue.global(qos: .userInitiated).async {
self._isLoading.send(true)
defer { self._isLoading.send(false) }
let reader = DXInstrumentProfileReader()
do {
let result = try reader.readFromFile(address: self.address)
guard let result else {
return promise(.success(.failure(ServerError.noData)))
}
let instrumentsData = result.map { ipf in
let timeZone = ipf.tradingHours.sliceMultipleTimes(from: "tz=", to: ";")
let data = Instrument(
type: ipf.type,
symbol: ipf.symbol,
description: ipf.descriptionStr,
timezone: timeZone.first ?? "America/New_York",
priceIncrements: ipf.priceIncrements
)
self.dataStorage.setTradingHours(symbol: ipf.symbol, tradingHours: ipf.tradingHours)
return data
}
self.instruments = instrumentsData
return promise(.success(.success(instrumentsData)))
} catch {
return promise(.success(.failure(ServerError.unknown)))
}
}
}
}.eraseToAnyPublisher()
init(_ address: String) {
self.address = address
}
}
fileprivate extension String {
func sliceMultipleTimes(from: String, to: String) -> [String] {
components(separatedBy: from).dropFirst().compactMap { sub in
(sub.range(of: to)?.lowerBound).flatMap { endRange in
String(sub[sub.startIndex ..< endRange])
}
}
}
}